package org.yak.common.file;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.imageio.stream.FileImageInputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import org.yak.common.utils.RandomUtil;
import org.yak.core.utils.ConfigUtils;
import org.yak.core.utils.DateUtil;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings("restriction")
public class FileUtil {

	private final static Logger logger = LoggerFactory.getLogger(FileUtil.class);

	/**
	 *
	 * @方法没描述：获取文件名，不含后缀
	 * @author XQ
	 * @param OriginalFilename
	 * @return
	 */
	public static String getFileName(String originalFilename) {
		return originalFilename.substring(0, originalFilename.indexOf("."));
	}

	/**
	 * 获取文件后缀名
	 *
	 * @param file
	 * @return
	 * @throws Exception
	 */
	public static String getFileExt(File file) throws Exception {
		if (file == null || StringUtils.isEmpty(file.getName())) {
			return null;
		}

		return getFileExt(file.getName());
	}

	/**
	 *
	 * @方法没描述：获取文件后最
	 * @author xq
	 * @param filename
	 * @return
	 * @throws Exception
	 */
	public static String getFileExt(String filename) throws Exception {
		return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
	}

	/**
	 * 存储通过spring方式上传的文件，返回上传后的路径
	 *
	 * @param file
	 * @param newFile
	 *            新文件存储的绝对路径目录
	 * @return 返回保存后的新文件名
	 * @throws Exception
	 */
	public static String saveToFile(MultipartFile file, String newFileDir) {
		try {
			File tempFile = new File(file.getOriginalFilename());
			if (tempFile == null || StringUtils.isEmpty(tempFile.getName())) {
				return "";
			}
			String newName = System.currentTimeMillis() + "." + getFileExt(tempFile);
			String filename = newFileDir + newName;
			createFile(filename);
			file.transferTo(new File(filename));
			return newName;
		} catch (Exception ex) {
			logger.error("图片存储失败");
			return "";
		}
	}

	public static boolean createFile(String filePath) throws Exception {
		File file = new File(filePath);
		if (!file.exists()) {
			makeDir(file.getParentFile());
		}
		return file.createNewFile();
	}

	/**
	 * Enhancement of java.io.File#mkdir() Create the given directory . If the
	 * parent folders don't exists, we will create them all.
	 *
	 * @see java.io.File#mkdir()
	 * @param dir
	 *            the directory to be created
	 */
	public static void makeDir(File dir) {
		if (!dir.getParentFile().exists()) {
			makeDir(dir.getParentFile());
		}
		dir.mkdir();
	}

	/**
	 * 递归删除目录下的所有文件及子目录下所有文件
	 *
	 * @param dir
	 *            将要删除的文件目录
	 * @return boolean Returns "true" if all deletions were successful. If a
	 *         deletion fails, the method stops attempting to delete and returns
	 *         "false".
	 */
	public static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		// 目录此时为空，可以删除
		return dir.delete();
	}

	/**
	 *
	 * @方法没描述：字节转换成KB
	 * @author xq
	 * @param fileSize
	 * @return
	 */
	public static String parseByteToKB(long fileSize) {
		double i = (fileSize / (1024.0));
		return String.valueOf(i);
	}

	/**
	 *
	 * @方法没描述：字节转换成MB
	 * @author xq
	 * @param bytes
	 * @return
	 */
	public static String parseByteToMB(long fileSize) {
		double i = (fileSize / (1024.0 * 1024.0));
		return String.valueOf(i);
	}

	/**
	 *
	 * @方法没描述：字节转换成GB
	 * @author xq
	 * @param fileSize
	 * @return
	 */
	public static String parseByteToGB(long fileSize) {
		double i = (fileSize / (1024.0 * 1024.0 * 1024.0));
		return String.valueOf(i);
	}

	/**
	 *
	 * @方法没描述：动态获取文件的大小，根据文件大小动态转换成GB，MB，KB，B单位
	 * @author xq
	 * @param size
	 * @return
	 */
	public static String getNetFileSizeDescription(long size) {
		StringBuffer bytes = new StringBuffer();
		DecimalFormat format = new DecimalFormat("###.0");
		if (size >= 1024 * 1024 * 1024) {
			double i = (size / (1024.0 * 1024.0 * 1024.0));
			bytes.append(format.format(i)).append("GB");
		} else if (size >= 1024 * 1024) {
			double i = (size / (1024.0 * 1024.0));
			bytes.append(format.format(i)).append("MB");
		} else if (size >= 1024) {
			double i = (size / (1024.0));
			bytes.append(format.format(i)).append("KB");
		} else if (size < 1024) {
			if (size <= 0) {
				bytes.append("0B");
			} else {
				bytes.append((int) size).append("B");
			}
		}
		return bytes.toString();
	}

	/**
	 * 保存文件 @方法没描述：
	 *
	 * @author XQ
	 * @param bfile
	 * @param fileURI
	 * @return
	 */
	public static long addFile(byte[] bfile, String fileURI) {
		BufferedOutputStream bos = null;
		FileOutputStream fos = null;
		File file = null;
		File dir = null;
		long filelength = 0L;
		try {
			dir = new File(fileURI.substring(0, fileURI.lastIndexOf("/") + 1).replace("/", "\\"));
			if (!dir.exists() && dir.isDirectory()) {// 判断文件目录是否存在
				dir.mkdirs();
			}
			file = new File(fileURI);
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			bos.write(bfile);
			filelength = file.length();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
		return filelength;
	}

	/**
	 * 将文件转成base64 字符串
	 * @param path文件路径
	 * @return *
	 * @throws Exception
	 */
	public static String encodeBase64File(String path) throws Exception {
		File file = new File(path);
		FileInputStream inputFile = new FileInputStream(file);
		byte[] buffer = new byte[(int) file.length()];
		inputFile.read(buffer);
		inputFile.close();
		return new BASE64Encoder().encode(buffer);
	}

	/**
	 * 将base64字符解码保存文件
	 * @param base64Code
	 * @param suffix		后缀名	例：rar/zip/txt
	 * @throws Exception
	 */
	public static String decoderBase64File(String base64Code,String suffix) throws Exception {
		//存放路径
		String targetPath = null;
		String fileName = RandomUtil.getRandom()+"."+suffix;
		String nowDate = DateUtil.nowDate();
		targetPath = ConfigUtils.getFileUploadDir() + File.separator+nowDate + File.separator + fileName;
		//targetPath = "D:/temp" + File.separator + nowDate + File.separator + fileName;
		File localFile = new File(targetPath);
        if(!localFile.getParentFile().exists()){
        	localFile.getParentFile().mkdirs();
        }
		byte[] buffer = new BASE64Decoder().decodeBuffer(base64Code);
		FileOutputStream out = new FileOutputStream(targetPath);
		out.write(buffer);
		out.close();
		return targetPath;
	}

	 /**
     * 删除单个文件
     *
     * @param fileName
     *            要删除的文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果文件路径所对应的文件存在，并且是一个文件，则直接删除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                System.out.println("删除单个文件" + fileName + "成功！");
                return true;
            } else {
                System.out.println("删除单个文件" + fileName + "失败！");
                return false;
            }
        } else {
            System.out.println("删除单个文件失败：" + fileName + "不存在！");
            return false;
        }
    }

    /**
     * 解压zip文件(批量用)
     * @param path	源路径
     * @return
     */
	public static List<String> unZip(String path) {
		List<String> result = new ArrayList<String>();
		int count = -1;
		File file = null;
		InputStream is = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		//解压文件目录
		String savepath = "";
		savepath = path.substring(0, path.lastIndexOf(File.separator)) + File.separator;
		new File(savepath).mkdir(); // 创建保存目录
		ZipFile zipFile = null;
		try {
			zipFile = new ZipFile(path,Charset.forName("GBK"));
			Enumeration<?> entries = zipFile.entries();

			while (entries.hasMoreElements()) {
				byte buf[] = new byte[2048];

				ZipEntry entry = (ZipEntry) entries.nextElement();

				String filename = RandomUtil.getRandom();
				boolean ismkdir = false;
				if (filename.lastIndexOf(File.separator) != -1) { // 检查此文件是否带有文件夹
					ismkdir = true;
				}
				filename = savepath + filename;

				if (entry.isDirectory()) { // 如果是文件夹先创建
					file = new File(filename);
					file.mkdirs();
					continue;
				}
				file = new File(filename);
				if (!file.exists()) { // 如果是目录先创建
					if (ismkdir) {
						new File(filename.substring(0, filename.lastIndexOf("/"))).mkdirs(); // 目录先创建
					}
				}
				file.createNewFile(); // 创建文件

				is = zipFile.getInputStream(entry);
				fos = new FileOutputStream(file);
				bos = new BufferedOutputStream(fos, 2048);

				while ((count = is.read(buf)) > -1) {
					bos.write(buf, 0, count);
				}
				bos.flush();
				bos.close();
				fos.close();
				is.close();
				result.add(filename);
			}
			zipFile.close();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try {
				if (bos != null) {
					bos.close();
				}
				if (fos != null) {
					fos.close();
				}
				if (is != null) {
					is.close();
				}
				if (zipFile != null) {
					zipFile.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	public static MultipartFile changeToMultipartFile(File file) throws IOException {
		FileInputStream input = new FileInputStream(file);
		MultipartFile multipartFile = new MockMultipartFile("file",file.getName(), "text/plain", IOUtils.toByteArray(input));
		return multipartFile;
	}
	
	/**
	 * 读取文件转换成字节数组
	 * @param path
	 * @return
	 */
	public static byte[] readFile2Byte(String path) {
		return readFile2Byte(new File(path));
	}
	
	/**
	 * 读取文件转换成字节数组
	 * @param file
	 * @return
	 */
	public static byte[] readFile2Byte(File file) {
		byte[] data = null;
		FileImageInputStream input = null;
		try {
			input = new FileImageInputStream(file);
			ByteArrayOutputStream output = new ByteArrayOutputStream();
			byte[] buf = new byte[1024];
			int numBytesRead = 0;
			while ((numBytesRead = input.read(buf)) != -1) {
				output.write(buf, 0, numBytesRead);
			}
			data = output.toByteArray();
			output.close();
			input.close();
		} catch (FileNotFoundException ex1) {
			ex1.printStackTrace();
		} catch (IOException ex1) {
			ex1.printStackTrace();
		}
		return data;
	}


	public static void main(String args[]) {
		/*String filePath = "/Users/zy/Documents/workspace-app/spider/spider-web/spider-web-api/src/main/webapp/upload/0/";
		try {
			boolean created = createFile(filePath);
			System.out.println(created ? "File created" : "File exists, not created.");
		} catch (Exception e) {
			e.printStackTrace();
		}*/

		//add by levin@20180324
		/*try {
			String base64Code = encodeBase64File("D:/1389789652(1).zip");
			String path = decoderBase64File(base64Code, "zip");
			List<String>  aaa = unZip(path);
			deleteFile(path);
			System.out.println(aaa.toString());
		}catch (Exception e) {
			e.printStackTrace();
		}*/
		
		//文件转base64
		try {
			String base64Code = encodeBase64File("D:/电缆、桥架及辅材模版-新0714.zip");
			System.out.println(base64Code);
		}catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}
